﻿using DataInterface.Model;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Timers;

namespace DataInterface
{
    public abstract class BaseDataTransmission : IDataTransmission, IDisposable
    {
        public event ErrorNoticedHandler ErrorNoticed;
        public event WarnNoticedHandler WarnNoticed;
        public event InfoNoticedHandler InfoNoticed;

        /// <summary>
        /// 传输通道类型
        /// </summary>
        protected abstract string TransmissionMark { get; }

        /// <summary>
        /// 传输配置
        /// </summary>
        protected IDataTransmissionConfig TransMissonConfig { get; set; }

        /// <summary>
        /// 定时器，用于失败数据传输
        /// </summary>
        protected System.Timers.Timer Timer_SendFaultData { get; set; }

        /// <summary>
        /// 前缀，用于友好日志
        /// </summary>
        protected string PreFix
        {
            get
            {
                return $"[{TransmissionMark}{(string.IsNullOrEmpty(TransMissonConfig?.Name) ? "" : $"({TransMissonConfig?.Name})")}]";
            }
        }

        protected object TimerLock = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="config"></param>
        public BaseDataTransmission(IDataTransmissionConfig config)
        {
            TransMissonConfig = config;
            Timer_SendFaultData = new System.Timers.Timer
            {
                Interval = config.ReTyrInterval * 1000,
                Enabled = config.ReTry
            };
            Timer_SendFaultData.Elapsed += Timer_Elapsed;
            Timer_SendFaultData.Start();
        }

        /// <summary>
        /// 传输数据
        /// </summary>
        /// <param name="processJsonData">需要传输的Json格式的数据</param>
        /// <returns></returns>
        public bool TransferData(string rawData, string processJsonData)
        {
            if (TransMissonConfig == null)
            {
                Error($"[{TransmissionMark}]传入配置为null，请联系开发人员");
                return false;
            }

            if (!TransMissonConfig.Valided())
            {
                Warn($"数据驱动配置不全,无法启用驱动.详情如下:{TransMissonConfig.Message}");
                return false;
            }

            if (!TransMissonConfig.Enabled)
            {
                Info($"传输未启用，此次数据不传输");
                return false;
            }


            Tuple<bool, string> result = new Tuple<bool, string>(false, string.Empty);
            switch (TransMissonConfig.TransmissionDataFormat)
            {
                case TransmissionDataFormat.RawData:
                    result = SendData(rawData);
                    break;
                case TransmissionDataFormat.ProcessedData:
                    result = SendData(processJsonData);
                    break;
            }

            if (!result.Item1)
            {
                Warn($"发送数据失败-{result.Item2};数据详情如下：{(TransMissonConfig.TransmissionDataFormat == TransmissionDataFormat.RawData ? rawData : processJsonData)}");
                FaultedDataSave(processJsonData);
                return false;
            }
            else
            {
                //发送成功
                Info($"发送数据成功,发送数据详情如下：{(TransMissonConfig.TransmissionDataFormat == TransmissionDataFormat.RawData ? rawData : processJsonData)}。response.content:{result.Item2}");
                return true;
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="content">需要传输的Json格式的数据</param>
        /// <returns>Item1:是否成功   Item2:消息</returns>
        protected abstract Tuple<bool, string> SendData(string content);

        /// <summary>
        /// 传输数据失败，将数据保存至本地数据库
        /// </summary>
        /// <param name="content"></param>
        protected abstract void FaultedDataSave(string content);

        /// <summary>
        /// 获取需要再次传输的失败数据
        /// </summary>
        /// <returns></returns>
        protected abstract List<FailedData> GetFaultData();

        /// <summary>
        /// 传输完成之后，需要处理的逻辑在此实现
        /// </summary>
        /// <param name="delList">传输成功或者不再传输需要从失败数据中删除的数据列表</param>
        /// <param name="updList">传输失败，需要更新传输次数的数据列表</param>
        /// <param name="successCount">传输成功的数据数量</param>
        /// <param name="faultCount">传输失败的数据数量</param>
        protected abstract void AfterTransferFaulted(List<FailedData> delList, List<FailedData> updList);

        /// <summary>
        /// 重新传输失败数据。
        /// </summary>
        /// <param name="content"></param>
        protected void TransferFaulted(List<FailedData> datas)
        {
            if (!TransMissonConfig.ReTry) return;
            List<FailedData> deleteList = new List<FailedData>();
            List<FailedData> updateList = new List<FailedData>();
            int successCount = 0;
            int faultCount = 0;
            foreach (var data in datas)
            {
                if (data != null)
                {
                    var result = SendData(data.Data);
                    if (result.Item1)
                    {
                        deleteList.Add(data);
                        successCount++;
                        continue;
                    }
                    faultCount++;
                    //如果重试次数大于等于设置的次数
                    if (data.ReTryCount >= TransMissonConfig.ReTryCount)
                    {
                        if (!TransMissonConfig.FaultDataRetention && TransMissonConfig.ReTryCount != 0)
                        {
                            deleteList.Add(data);
                        }
                        else
                        {
                            //增加一次重试次数保存至数据库
                            data.ReTryCount++;
                            updateList.Add(data);
                        }
                    }
                    else
                    {
                        //增加一次重试次数保存至数据库
                        data.ReTryCount++;
                        updateList.Add(data);
                    }
                }
            }

            AfterTransferFaulted(deleteList, updateList);

            if (successCount == 0 && faultCount == 0) return;
            Info($"失败数据重试共{successCount + faultCount}条数据，成功{successCount}条，失败{faultCount}条");

        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (Monitor.TryEnter(TimerLock))
            {
                try
                {
                    var data = GetFaultData();
                    TransferFaulted(data);
                }
                catch (Exception ex)
                {
                    Error(ex.Message);
                }
                finally
                {
                    Monitor.Exit(TimerLock);
                }
            }
        }

        protected void Info(string msg)
        {
            InfoNoticed?.Invoke($"{PreFix}{msg}");
        }

        protected void Warn(string msg)
        {
            WarnNoticed?.Invoke($"{PreFix}{msg}");
        }

        protected void Error(string msg)
        {
            ErrorNoticed?.Invoke($"{PreFix}{msg}");
        }

        public void Dispose()
        {
            Timer_SendFaultData.Stop();
            Timer_SendFaultData.Dispose();
        }
    }
}
